package vsvm.classifier;

import java.util.Iterator;

import org.apache.commons.math.random.RandomDataImpl;

import vsvm.graphics.charts.ProbabilityChart;
import libsvm.svm;
import libsvm.svm_node;
import libsvm.svm_model;
import libsvm.svm_problem;
import vsvm.gui.Environment;
import vsvm.gui.VSVMInternalFrame;
import vsvm.gui.forms.AUCTestDialog;
import vsvm.gui.forms.ClassificationResultsFrame;
import vsvm.gui.forms.PNROCFrame;
import vsvm.gui.forms.ROCFrame;
import vsvm.gui.forms.SummaryDialog;
import vsvm.gui.forms.McNemarTestDialog;

public class MultiLibSvmTestSet extends  LibSvmTestSet{
    
        private static final long serialVersionUID = 100L;
	
	private static final String AC_SUMMARY = "Summary";
	private static final String AC_RESULTS = "Results";
	private static final String AC_PROB_CHART  = "Probability chart";
	private static final String AC_McNemarTest = "Mcnemar's Test";
	private static final String AC_AUCTest = "AUC Test";
	private static final String AC_ROC_CURVE   = "ROC curve";
	private static final String AC_PN_ROC_CURVE = "PN ROC curve";
    
    private LibSvmClassifier cls;
	private TestingParameters p;
        
        public MultiLibSvmTestSet(LibSvmClassifier c, TestingParameters p) {
                super(c, p);
		this.p = p;
		cls = c;	
	}

    
    	public void execute() {
			switch (p.getTestType()) {
			
			case TestingParameters.TEST_TRAINING_DATA:                                            
				
				svm_problem prob = cls.convertDataModel(p.getTrainDataModel());
				long t1 = System.currentTimeMillis();
				svm_model model = svm.svm_train(prob, cls.getParameter());
				trainTime = System.currentTimeMillis() - t1;
	                        
	            int numberOfClasses = svm.svm_get_nr_class(model);
				
				int[] lbl = new int[numberOfClasses];
				svm.svm_get_labels(model, lbl);
				
				t1 = System.currentTimeMillis();
				for (int i = 0; i < prob.x.length; ++i) {
					double[] pro = new double[numberOfClasses]; 
					double pval = svm.svm_predict_probability(model, prob.x[i], pro);
					testCases.add(new MultiTestCase(null, pval, prob.y[i], pro, lbl));
				}
				testTime = System.currentTimeMillis() - t1;
				break;
				
			case TestingParameters.TEST_SEPARATE_DATA:
				
	            svm_problem probTest = cls.convertDataModel(p.getTestDataModel());
	           // System.out.println((p.getTrainDataModel()).toString());   
	            model = p.getTrainedDataModel();
	            
	            t1 = System.currentTimeMillis();
	            if(model == null){
	            	prob = cls.convertDataModel(p.getTrainDataModel());
	            	t1 = System.currentTimeMillis();
		            model = svm.svm_train(prob, cls.getParameter());
	            }

				trainTime = System.currentTimeMillis() - t1;
	                        
	            numberOfClasses = svm.svm_get_nr_class(model);
				
				lbl = new int[numberOfClasses];
				svm.svm_get_labels(model, lbl);			
				
				t1 = System.currentTimeMillis();
				for (int i = 0; i < probTest.x.length; ++i) {
					double[] pro = new double[numberOfClasses]; 
					double pval = svm.svm_predict_probability(model, probTest.x[i], pro);
	                                //System.out.println(prob1.y[i]);
					testCases.add(new MultiTestCase(null, pval, probTest.y[i], pro, lbl));// buvo prob.y[i]
				}
				testTime = System.currentTimeMillis() - t1;
				
				break;
			case TestingParameters.TEST_SPLIT_DATA:
				prob = cls.convertDataModel(p.getTrainDataModel());
				RandomDataImpl rdi = new RandomDataImpl();
				int[] perm;
				if (p.isRandom())
					perm = rdi.nextPermutation(prob.x.length, prob.x.length);
				else {
					perm = new int[prob.x.length];
					for (int i = 0; i < prob.x.length; ++i) 
						perm[i] = i;
				}
				svm_problem subproblem = new svm_problem();
				subproblem.l = p.getSplit();
				subproblem.y = new double[p.getSplit()];
				subproblem.x = new svm_node[p.getSplit()][];
				for (int i = 0; i < p.getSplit(); ++i) {
					subproblem.y[i] = prob.y[perm[i]];
					subproblem.x[i] = prob.x[perm[i]];
				}
					
				t1 = System.currentTimeMillis();
				model = svm.svm_train(subproblem, cls.getParameter());
				trainTime = System.currentTimeMillis() - t1;
				
	                        numberOfClasses = svm.svm_get_nr_class(model);
	                        
				lbl = new int[numberOfClasses];
				svm.svm_get_labels(model, lbl);
							
				t1 = System.currentTimeMillis();
				for (int i = 0; i < prob.x.length - subproblem.x.length; ++i) {
					double[] pro = new double[numberOfClasses]; 
					double pval = svm.svm_predict_probability(model, prob.x[perm[subproblem.x.length+i]], pro);
					testCases.add(new MultiTestCase(null, pval, prob.y[perm[subproblem.x.length+i]], pro, lbl));
				}
				testTime = System.currentTimeMillis() - t1;
				
				break;
			case TestingParameters.TEST_CROSS_VALIDATION:
				prob = cls.convertDataModel(p.getTrainDataModel());
				int dn = prob.l/p.getFolds();
				int mn = prob.l%p.getFolds();
				int s, e = 0;
				testTime = trainTime = 0;
				for (int i = 0; i < p.getFolds(); ++i) {
					int t = (mn-- > 0) ? dn + 1 : dn;
					subproblem = new svm_problem();
					subproblem.l = prob.l - t;
					subproblem.y = new double[subproblem.l];
					subproblem.x = new svm_node[subproblem.l][];
					s = e;
					e = e + t;
					for (int j = 0, k = 0; j < prob.l; ++j) {
						if (j < s || j >= e) {
							subproblem.y[k] = prob.y[j];
							subproblem.x[k] = prob.x[j];
							++k;
						}
					}
					t1 = System.currentTimeMillis();
					model = svm.svm_train(subproblem, cls.getParameter());
					trainTime += System.currentTimeMillis() - t1;
	                                
	                                numberOfClasses = svm.svm_get_nr_class(model);
	                                
					lbl = new int[numberOfClasses];
					svm.svm_get_labels(model, lbl);
					t1 = System.currentTimeMillis();
					for (int j = s; j < e; ++j) {
						double[] pro = new double[numberOfClasses]; 
						double pval = svm.svm_predict_probability(model, prob.x[j], pro);
						testCases.add(new MultiTestCase(null, pval, prob.y[j], pro, lbl));
					}
					testTime += System.currentTimeMillis() - t1;
				}			
				break;
			}		
	}
        
        public void executeAction(String action) {
		if (action.equals(AC_SUMMARY)) {
			int r = 0, w = 0;
			int fp = 0, fn = 0;
			
			for (Iterator<TestCase> i = testCases.iterator(); i.hasNext();) {
				TestCase tc = i.next();
				if (Math.abs(tc.ac - tc.pc) < 1e-8) ++r;
				else {
					++w;
					if (tc.ac > tc.pc) ++fn;
					else ++fp;
				}
			}
		
			Object[][] data = new Object[6][];
			for (int i = 0; i < 6; ++i) data[i] = new Object[2];
			data[0][0] = "Training time (ms)";
			data[0][1] = trainTime;
			data[1][0] = "Testing time (ms)";
			data[1][1] = testTime;
			data[2][0] = "Number of samples";
			data[2][1] = testCases.size();
			data[3][0] = "Classified right";
			data[3][1] = r;
			data[4][0] = "Classified wrong";
			data[4][1] = w;
			data[5][0] = "Accuracy %";
			data[5][1] = r*100.0/((double)r+w);
			
			SummaryDialog f = new SummaryDialog("Test summary for " + name, data);
						
			Environment.getEnvironment().getMainFrame().addWindow(f);
			f.setVisible(true);
			
		}
		else if (action.equals(AC_RESULTS)) {
			ClassificationResultsFrame f = new ClassificationResultsFrame(name, testCases);
			f.setVisible(true);
			Environment.getEnvironment().getMainFrame().addWindow(f);
			
		} 
		else if (action.equals(AC_PROB_CHART)){
			
			ProbabilityChart pChart = new ProbabilityChart(this, "Probability Chart");
			VSVMInternalFrame iframe = new VSVMInternalFrame("Probability chart");
			iframe.getContentPane().add(pChart);
			
			
			Environment.getEnvironment().getMainFrame().addWindow(iframe);
			iframe.setVisible(true);
			
		}
		else if (action.equals(AC_McNemarTest)) {
			McNemarTestDialog MNTestDialog = new McNemarTestDialog(this);
			MNTestDialog.setVisible(true);
		} else if (action.equals(AC_AUCTest)) {
			AUCTestDialog aucTestDialog = new AUCTestDialog(this);
			aucTestDialog.setVisible(true);
		} 
		else if (action.equals(AC_ROC_CURVE)) {
			ROCFrame iframe = new ROCFrame(this);
			Environment.getEnvironment().getMainFrame().addWindow(iframe);
			iframe.setVisible(true);
		}
		else if (action.equals(AC_PN_ROC_CURVE)) {
			PNROCFrame iframe = new PNROCFrame(this);
			Environment.getEnvironment().getMainFrame().addWindow(iframe);
			iframe.setVisible(true);
		}
	}

}
	
